#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dbus/dbus.h>
#include <unistd.h>


#include <iostream>
#include <string>
#include <memory>

using namespace std;

#include "cJSON.h"


// 接收数据
typedef struct Data
{
    string name;
    int age;

} _Data;


void parseJsonStr(char *pstr)
{
    // 解析json数据
    cJSON *pParseJson = cJSON_Parse(pstr);
    if ( pParseJson == nullptr )
    {
        printf("error: %s\n", strerror(errno));
        return ;
    }

    cJSON *pName = cJSON_GetObjectItem(pParseJson, "name");
    cJSON *pAge = cJSON_GetObjectItem(pParseJson, "age");

    // 赋值数据
    _Data data;
    data.name = pName->valuestring;
    data.age = pAge->valueint;

    printf("Parse json - name: %s, age: %d\n", data.name.c_str(), data.age);

}



//建立与session D-Bus daemo的连接，并设定连接的名字，相关的代码已经多次使用过了
DBusConnection* connect_dbus(DBusError &err)
{
    //    DBusError err;
    DBusConnection *connection;
    int ret;

    //Step 1: connecting session bus

    dbus_error_init(&err);

    connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr, "ConnectionErr : %s\n", err.message);
        dbus_error_free(&err);
    }
    if(connection == NULL)
    {
        printf("%d - error: %s\n", __LINE__, strerror(errno));
        return NULL;
    }

    //step 2: 设置BUS name，也即连接的名字, test.wei.recvSignal为唯一连接名
    ret = dbus_bus_request_name(connection, "test.wei.recvSignal", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
    if(dbus_error_is_set(&err)){
        fprintf(stderr, "Name Err :%s\n", err.message);
        dbus_error_free(&err);
    }
    if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    {
        printf("%d - error: %s\n", __LINE__, strerror(errno));
        return NULL;
    }

    return connection;
}


void recvSignal(DBusConnection *connection, DBusError &err)
{

    DBusMessage *msg;
    DBusMessageIter arg;
    int ret;
    char * sigvalue;
    int interVal = 0;


    //步骤3:通知D-Bus daemon，希望监听来行接口test.signal.Type的信号
    dbus_bus_add_match(connection, "type='signal', interface='test.signal.Type'", &err);

    //实际需要发送东西给daemon来通知希望监听的内容，所以需要flush
    dbus_connection_flush(connection);
    if(dbus_error_is_set(&err))
    {
        fprintf(stderr, "Match Error%s\n", err.message);
        dbus_error_free(&err);
    }

    //步骤4:在循环中监听，每隔开1秒，就去试图自己的连接中获取这个信号。这里给出的是从连接中获取任何消息的方式，所以获取后去检查一下这个消息是否我们期望的信号，并获取内容。我们也可以通过这个方式来获取method call消息。
    while(1)
    {
        dbus_connection_read_write(connection, 0);
        msg = dbus_connection_pop_message(connection);
        if(msg == NULL){
            usleep(80);
            continue;
        }

        if(dbus_message_is_signal(msg, "test.signal.Type", "Test"))
        {
            if(!dbus_message_iter_init(msg, &arg))
            {
                // 没有参数
                fprintf(stderr, "Message Has no Param");
            }

//            :1.611就是dbus-send在本次调用中与会话总线所建立连接的唯一名     dbus_message_get_sender 获取的是建立连接的为唯一名
            const char *pInfo = dbus_message_get_sender(msg);

            if ( dbus_message_iter_get_arg_type(&arg) == DBUS_TYPE_STRING )
            {
                dbus_message_iter_get_basic(&arg, &sigvalue);
                printf("Got Singal with str value:\n%s\nID: %s\n\n", sigvalue, pInfo);

                // 反序列化，转换成原始数据
                parseJsonStr(sigvalue);

            }

            if ( dbus_message_iter_get_arg_type(&arg) == DBUS_TYPE_UINT32 )
            {
                dbus_message_iter_get_basic(&arg, &interVal);
                printf("Got Singal with inter value : %d - ID: %s\n", interVal, pInfo);
            }

#if 0
            else if(dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_STRING)
                fprintf(stderr, "Param is not string");
            else if (dbus_message_iter_get_arg_type(&arg) != DBUS_TYPE_UINT32)
                fprintf(stderr, "Param is not int");
            else
                dbus_message_iter_get_basic(&arg, &sigvalue);
#endif

        }

        dbus_message_unref(msg);
    }//End of while

}



int main()
{

    printf("---------------- Recv Signal ----------------\n");

    DBusError err;
    DBusConnection *pConnect = connect_dbus(err);
    if ( nullptr == pConnect )
    {
        printf("LINE: %d - %s\n", __LINE__, strerror(errno));
        return -1;
    }

    // 接收总线信号
    recvSignal(pConnect, err);


    printf("Recv Signal Finish.\n");

    return 0;
}
